package main

import (
	"fmt"
	"github.com/docker/docker/api/types"
	"io/ioutil"
	"net/http"
	"os/exec"
	"protector/docker/docker_server"
	"protector/listener/timer"
	"protector/request"
	"strings"
)

const (
	ApiUrl = "https://open.feishu.cn/open-apis/bot/v2/hook/dd624e70-630a-48a9-b005-eff2abdae077"
	//最大尝试重启次数
	MAX_TRY_COUNT = 2
	LISTEN_TIME   = 3
)

func main() {
	//println("启动守护进程")
	sendMsg("启动监控程序")
	StartSystemListen()
	StartErrorInfoSend()
}

func execKill() {
	// 返回一个 cmd 对象
	cmd := exec.Command("sh", "-c", "./kills.sh")

	// 如果只执行命令，不接收返回值
	err := cmd.Run()
	if err != nil {
		sendMsg("执行恶意程序清除任务失败，请上线查看!")
	}
}

func NewContainer(container types.Container) error {
	return nil
}

func CompateList(oldList []types.Container, newList []types.Container) []types.Container {
	return nil
}

func sendMsg(text string) {

	fmt.Println(text)

	//构建消息
	message := request.NewFeishuMessage("线上服务器", text)

	msgStr := fmt.Sprintf("{\"msg_type\":\"%s\",\"card\":%s}", message.MsgType, message.Card)

	//fmt.Println(msgStr)

	// 发送请求
	resp, err := http.Post(ApiUrl, "application/json", strings.NewReader(msgStr))
	if err != nil {
		panic(err)
	}

	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}

	fmt.Println(string(body))

}

func NewExitedContain() {

}

//开始系统监听

func StartSystemListen() {

	server, err := docker_server.NewDockerServer()

	if err != nil {
		panic(err)
	}

	//获取所有容器
	containers, err := server.ListContainers()

	if err != nil {
		panic(err)
	}

	if len(containers) == 0 {
		println("没有需要维护的容器列表")
	}

	println("维护容器列表如下")

	containersStr := ""
	for i := 0; i < len(containers); i++ {
		containersStr += containers[i].Names[0] + ","
	}

	fmt.Println("系统初始化成功，维护容器如下: " + containersStr)

	//listens
	listens := func() {

		//开始定时扫描
		//fmt.Println("开始定时扫描")

		//获取最新列表
		newContainers, err := server.ListContainers()

		if err != nil {
			panic(err)
		}

		//containersStr = ""
		//for i := 0; i < len(containers); i++ {
		//	containersStr += containers[i].Names[0] + ","
		//}
		//
		//sendMsg("监听时扫描容器如下: " + containersStr)
		//判断已经挂掉的容器
		for i := 0; i < len(newContainers); i++ {

			if InList(newContainers[i], containers) == false && newContainers[i].State == "running" {
				//尝试重新启动或者停止
				tryCount := 0

			stoptContain:
				if tryCount > MAX_TRY_COUNT {
					sendMsg(fmt.Sprintf("恶意容器%s停止%d次失败，请上线查看！", newContainers[i].Names[0], MAX_TRY_COUNT+1))
				}
				tryCount++
				sendMsg(fmt.Sprintf("恶意容器 %s 尝试第%d次停止", newContainers[i].Names[0], tryCount))
				//停止容器
				err := server.StopContainer(newContainers[i].ID)

				if err != nil {
					goto stoptContain
				}
				sendMsg(fmt.Sprintf("恶意容器%s检测到运行，停止成功！", newContainers[i].Names[0]))
			}

			//需要进行关闭或者重启
			if CheckList(newContainers[i], containers) {
				//尝试重新启动或者停止
				tryCount := 0

				//重新启动
			restartContain:
				tryCount++

				if tryCount > MAX_TRY_COUNT {
					//发送消息并重新创建容器
					sendMsg(fmt.Sprintf("容器%s重启%d次失败，请上线查看！", newContainers[i].Names[0], MAX_TRY_COUNT+1))
					NewExitedContain()
				}

				sendMsg(fmt.Sprintf("容器 %s 尝试第%d次重启", newContainers[i].Names[0], tryCount))

				if newContainers[i].State == "exited" {
					err := server.RestartContainer(newContainers[i].ID)

					if err != nil {
						goto restartContain
					}
					sendMsg(fmt.Sprintf("%s检测到停止运行，重启成功！", newContainers[i].Names[0]))
				}

			}

		}

		//比较两个列表
		resList := CompateList(containers, newContainers)

		if resList != nil {

			//循环创建
			for i := 0; i < len(resList); i++ {
				container := resList[i]
				//创建容器
				err := NewContainer(container)

				if err != nil {
					panic(err)
				}
			}

			//创建完毕，更新维护的列表
			containers, err = server.ListContainers()

			if err != nil {
				panic(err)
			}
		}

	}
	//启动监听
	timerVar := timer.Timer{
		Interval: LISTEN_TIME,
	}

	timerVar.Task = listens

	//启动扫描

	timerVar.Start()

	//启动定时任务杀死恶意进程
	killTimer := timer.Timer{
		Interval: 60 * 60 * 24,
	}
	killTimer.Task = execKill
	killTimer.Start()

}

// 开启容错信息发送
func StartErrorInfoSend() {
	// 定义一个处理器函数
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		r.ParseForm()
		msg := r.PostFormValue("msg")
		sendMsg(msg)
	})

	// 设置监听的端口
	err := http.ListenAndServe(":6666", nil)
	if err != nil {
		panic(err)
	}
}

func CheckList(val types.Container, array []types.Container) bool {
	flag := InList(val, array)

	if flag {
		for _, item := range array {
			if item.ID == val.ID && item.State == "running" && val.State == "exited" {
				return true
			}
		}
	}

	return false
}

func InList(val types.Container, array []types.Container) bool {
	for _, item := range array {
		if item.ID == val.ID && item.State == "running" {
			return true
		}
	}

	return false
}
